package net.andersand.games.yatzy;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.JOptionPane;

import net.andersand.games.yatzy.Dice.Die;

/**
 * 
 * @author Anders Sandberg Nordbø
 */
class YatzyFrame extends JFrame {
	/** */
	private static final long serialVersionUID = 1;

	static final String RESOURCES = "/res/";
	static final String IMAGES = RESOURCES + "img/";
	static final String SOUNDS = RESOURCES + "sound/";

	private YatzyListener listener;
	private Sound sound;
	private List<JButton> dieButtons;

	/**
	 * Currently used to show messages like <tt>It's your turn player 2</tt>
	 * and analysis eg. <tt>
	 * You currently have <ul>
	 * <li>Pair</li>
	 * <li>Three of a kind</li></ul>
	 */
	private JTextArea messages;
	private JButton rollButton;
	private JTable table;

	private boolean gameOver = false;

	YatzyFrame(List<String> playerNames) {
		super("Yatzy");
		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				int endNow = JOptionPane.showConfirmDialog(
						null, "End game?", "Yatzy", JOptionPane.YES_NO_OPTION);
				if (endNow == 0) {
					JOptionPane.showMessageDialog(
							null, listener.endGame(), "Scores", JOptionPane.INFORMATION_MESSAGE);
					System.exit(0);
				}
			}
			
		});
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		}
		catch (Exception e) {
		}
		sound = new DefaultSound(Resources.get(SOUNDS + "dicethrow.wav"));
		List<Image> icons = new ArrayList<Image>();
		icons.add(new ImageIcon(Resources.get(IMAGES + "icon32.gif")).getImage());
		icons.add(new ImageIcon(Resources.get(IMAGES + "icon16.gif")).getImage());
		setIconImages(icons);
		Container c = getContentPane();
		c.setLayout(new GridBagLayout());
		GridBagConstraints constr = new GridBagConstraints();
		constr.gridx = constr.gridy = 0;
		constr.weightx = constr.weighty = 1;
		constr.gridwidth = constr.gridheight = 1;
		constr.insets = new Insets(5,5,5,5);
		rollButton = new JButton(new ImageIcon(Resources.get(IMAGES + "diceroll.png")));
		rollButton.setToolTipText("Roll your dice");
		rollButton.setDisabledIcon(new ImageIcon(Resources.get(IMAGES + "nodiceroll.gif")));
		rollButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sound.play();
				listener.rollDices();
			}
		});
		c.add(rollButton, constr);
		dieButtons = new ArrayList<JButton>();
		for (int i = 0; i < Yatzy.NUMBER_OF_DICES; i++) {
			JButton b = new JButton(new DieIcon(0, false));
			final int j = i;
			b.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					fireToggleDie(j);
				}
			});
			dieButtons.add(b);
			constr.gridx++;
			c.add(b, constr);
		}

		constr.gridx = 0;
		constr.gridy++;
		constr.fill = GridBagConstraints.HORIZONTAL;
		constr.gridwidth = 6; // 5 dices + 1 rollbutton
		addTableVC(c, constr, playerNames);

		constr.gridy++;
		constr.gridheight = 3;
		constr.fill = GridBagConstraints.BOTH;
		messages = new JTextArea("Ready.\n\n");
		messages.setLineWrap(true);
		messages.setWrapStyleWord(true);
		messages.setEditable(false);
		JScrollPane scroll = new JScrollPane(messages);
		c.add(scroll, constr);

		pack();
		int x = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth()
				/ 2 - getWidth() / 2;
		int y = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight()
				/ 2 - getHeight() / 2;
		setBounds(x, y, getWidth(), getHeight());	
		table.repaint();
		setVisible(true);
	}

	/**
	 * Adds a yatzy table to the window
	 * 
	 * @param c
	 * @param playerNamesArg
	 */
	private void addTableVC(Container c, GridBagConstraints constr, final List<String> playerNamesArg) {
		table = new JTable(new AbstractTableModel() {

			private static final long serialVersionUID = 1;
			
			private List<String> playerNames = playerNamesArg;

			public int getColumnCount() {
				return playerNames.size() + 1;
			}

			public int getRowCount() {
				// for now need as many rows as there are score types
				return ScoreType.values().length;
			}

			@Override
			public String getColumnName(int column) {
				if (column == 0) {
					return "";
				}
				return playerNames.get(column - 1);
			}

			public Object getValueAt(int rowIndex, int columnIndex) {
				if (listener == null) {
					return "";
				}
				if (columnIndex == 0) {
					return ScoreType.values()[rowIndex].getName();
				}
				Player p = listener.getPlayer(columnIndex);
				if (p != null) {
					Score s = p.getScoreKeeper().findScoreByOrdinal(rowIndex);
					if (s == null) {
						return "";
					}
					return s.getValue();
				}
				return null;
			}

		});
		table.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (!rollButton.isEnabled()) {
					int rowIndex = table.rowAtPoint(e.getPoint());
					// update player score and get value in return
					Score score = listener.setScore(ScoreType.values()[rowIndex]);
					if (score != null) {
						// update table with the value in the player's column
						table.setValueAt(score.getValue(), rowIndex, score.getPlayerID());
						table.repaint();
						// clear the player's dice
						listener.resetPlayerTurn();
						// show empty dice, signalling the next player can go
						displayThrow(listener.getPlayer(score.getPlayerID()).getDice());
						if (!gameOver) {							
							// display a message for the next player
							messages.setText(listener.getNextPlayer().getName() + " it's your turn!");
							// enable the button
							rollButton.setEnabled(true);						
						}
					}
				}
			}

		});
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		panel.add(table.getTableHeader(), BorderLayout.PAGE_START);
		panel.add(table, BorderLayout.PAGE_END);
		c.add(panel, constr);
	}

	/**
	 * Toggle the selected die and set icon accordingly.
	 * 
	 * @param index
	 */
	private void fireToggleDie(int index) {
		Die die = listener.toggleLockDie(index);
		JButton button = dieButtons.get(index);
		button.setIcon(new DieIcon(die.getValue(), die.isLocked()));
	}

	/**
	 * Displays the thrown dices
	 * 
	 * @param dices
	 */
	void displayThrow(Dice dice) {
		int index = 0;
		for (Dice.Die d : dice.getDice()) {
			JButton b = dieButtons.get(index++);
			b.setIcon(new DieIcon(d.getValue(), d.isLocked()));
		}
	}

	/**
	 * 
	 */
	void displayResult(String s) {
		messages.setText(s);
	}

	void setListener(YatzyListener listener) {
		this.listener = listener;
	}

	/**
	 * Invoked when player turn complete. The button to roll is disabled, the
	 * player is asked to select a score, and when that's been chosen, the
	 * button is enabled and next player can go.
	 * 
	 * @param dice
	 */
	public void chooseScore(Dice dice) {
		rollButton.setEnabled(false);
		messages.setText("Click the score you want to use for these dice. "
				+ messages.getText());
	}

	public void setGameOver() {
		rollButton.setEnabled(false);
		gameOver  = true;
		// do something else like letting the user start a new game here
	}

}
